package test.dialogs.pages;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import com.ahmedmisbah.andgenplus.codegenerator.CodeGenerator;
import com.ahmedmisbah.andgenplus.codegenerator.CodeGeneratorFactory;
import com.ahmedmisbah.andgenplus.constants.GlobalConstants;
import com.ahmedmisbah.andgenplus.restgenerator.beans.Parameter;
import com.ahmedmisbah.andgenplus.restgenerator.beans.RESTWebServiceDescriptor;
import com.ahmedmisbah.andgenplus.utils.string.StringUtil;

public class RESTWizardPageOne extends WizardPage {

	private Text webServiceName;
	private Text operationName;
	private Text packagePath;
	private Text webServiceURL;
	private Text jsonReturn;

	private Combo webServiceOperationType;
	private Combo urlFormat;

	private Composite parent;
	private GridData gridData;
	private ScrolledComposite scrollableComposite;
	private Composite parameterComposite;
	private GridLayout parameterLayout;
	private int paramaterCount = 1;

	private List<Parameter> parameterList = new ArrayList<Parameter>();

	List<ParameterUIComponent> parameterUIComponentList = new ArrayList<ParameterUIComponent>();

	public RESTWizardPageOne() {
		super("Step 1");
		setTitle("Step 1/2");
		setDescription("This page generates integeration and business tier classes");
	}

	@Override
	public void createControl(Composite shellComposite) {
		parent = new Composite(shellComposite, SWT.NULL);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);

		// The text fields will grow with the size of the dialog
		gridData = new GridData();
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;

		Label label0 = new Label(parent, SWT.NONE);
		label0.setText("Package Path");

		packagePath = new Text(parent, SWT.BORDER);
		packagePath.setLayoutData(gridData);

		Label label1 = new Label(parent, SWT.NONE);
		label1.setText("Webservice Name");

		webServiceName = new Text(parent, SWT.BORDER);
		webServiceName.setLayoutData(gridData);

		Label label2 = new Label(parent, SWT.NONE);
		label2.setText("Webservice URL");

		webServiceURL = new Text(parent, SWT.BORDER);
		webServiceURL.setLayoutData(gridData);

		Label label3 = new Label(parent, SWT.NONE);
		label3.setText("Webservice Operation");

		operationName = new Text(parent, SWT.BORDER);
		operationName.setLayoutData(gridData);

		Label label4 = new Label(parent, SWT.NONE);
		label4.setText("JSON Return");

		GridData textAreaGridData = new GridData();
		textAreaGridData.grabExcessHorizontalSpace = true;
		textAreaGridData.horizontalAlignment = GridData.FILL;
		textAreaGridData.heightHint = 100;

		jsonReturn = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
		jsonReturn.setLayoutData(textAreaGridData);

		Label label5 = new Label(parent, SWT.NONE);
		label5.setText("Operation Type");

		webServiceOperationType = new Combo(parent, SWT.READ_ONLY);
		webServiceOperationType.setItems(new String[] { "GET", "POST", "PUT",
				"DELETE" });
		webServiceOperationType.setLayoutData(gridData);

		Label label6 = new Label(parent, SWT.NONE);
		label6.setText("URL Format");

		urlFormat = new Combo(parent, SWT.READ_ONLY);
		urlFormat.setItems(new String[] { RESTWebServiceDescriptor.AND_VALUE,
				RESTWebServiceDescriptor.SLASH_VALUE });
		urlFormat.setLayoutData(gridData);

		/*--------------------------------------------------------------------------*/

		Label label7 = new Label(parent, SWT.NONE);
		label7.setText("Webservice Parameters");

		parameterLayout = new GridLayout();
		parameterLayout.numColumns = 6;

		GridData parameterCompositeGridData = new GridData();
		parameterCompositeGridData.grabExcessHorizontalSpace = true;
		parameterCompositeGridData.horizontalAlignment = GridData.FILL;
		// parameterCompositeGridData.heightHint = 100;
		// parameterCompositeGridData.widthHint = 500;

		scrollableComposite = new ScrolledComposite(parent, SWT.BORDER
				| SWT.V_SCROLL);

		parameterComposite = new Composite(scrollableComposite, SWT.NONE);
		// parameterComposite.setLayoutData(parameterCompositeGridData);
		parameterComposite.setLayout(parameterLayout);
		parameterComposite.setSize(600, 200);

		scrollableComposite.setContent(parameterComposite);

		scrollableComposite.setMinWidth(500);
		scrollableComposite.setMinHeight(100);
		scrollableComposite.setExpandHorizontal(true);
		scrollableComposite.setExpandVertical(true);

		Label label8 = new Label(parent, SWT.NONE);
		label8.setText("");

		createAddParameterButton(parent, Window.OK, "Add Parameter");

		Label label9 = new Label(parent, SWT.NONE);
		label9.setText("");

		createGenerateCodeButton(parent, Window.OK, "Generate Code");

		setControl(parent);
		setPageComplete(false);

	}

	private void createAddParameterButton(Composite parent, int id, String label) {

		Button button = new Button(parent, SWT.PUSH);
		button.setText(label);
		button.setFont(JFaceResources.getDialogFont());
		button.setData(new Integer(id));

		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				Label parameterNameLabel = new Label(parameterComposite,
						SWT.NONE);

				ParameterUIComponent parameterUIComponent = new ParameterUIComponent();
				parameterNameLabel
						.setText("Param" + paramaterCount++ + " Name");

				Text parameterNameText = new Text(parameterComposite,
						SWT.BORDER);
				parameterNameText.setLayoutData(gridData);
				parameterUIComponent.setParameterNameText(parameterNameText);

				Label parameterValueLabel = new Label(parameterComposite,
						SWT.NONE);
				parameterValueLabel.setText("Default Value");

				Text parameterValueText = new Text(parameterComposite,
						SWT.BORDER);
				parameterValueText.setLayoutData(gridData);
				parameterUIComponent.setParameterValueText(parameterValueText);

				Combo parameterType = new Combo(parameterComposite,
						SWT.READ_ONLY);
				parameterType.setItems(new String[] { "Integer", "Long",
						"Float", "Double", "Boolean", "String" });
				parameterType.setLayoutData(gridData);
				parameterUIComponent.setParameterType(parameterType);

				parameterUIComponentList.add(parameterUIComponent);

				Button button = new Button(parameterComposite, SWT.PUSH);
				button.setText("Delete");
				button.setLayoutData(gridData);

				scrollableComposite.setMinSize(parameterComposite.computeSize(
						SWT.DEFAULT, SWT.DEFAULT));

				parameterComposite.layout();
				scrollableComposite.layout();
				parameterComposite.getParent().layout();

			}
		});

	}

	private void createGenerateCodeButton(Composite parent, int id, String label) {

		Button button = new Button(parent, SWT.PUSH);
		button.setText(label);
		button.setFont(JFaceResources.getDialogFont());
		button.setData(new Integer(id));

		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {

				try {
					generateAndroidScreen();
					setMessage("Classes generated successfully", INFORMATION);
					setPageComplete(true);
				} catch (Exception e) {
					e.printStackTrace();
					setErrorMessage(e.getMessage());
				}

			}
		});

	}

	@Override
	public IWizardPage getNextPage() {
		RESTWizardPageTwo pageTwo = (RESTWizardPageTwo) super.getNextPage();
		pageTwo.renderPageItems();

		return pageTwo;
	}

	private void generateAndroidScreen() throws Exception {

		validateInputs();

		/** This code was only for testing **/
		/*
		 * final String JSON_FILE_PATH = GlobalConstants.WINDOWS_D_DRIVE +
		 * File.separator + GlobalConstants.AND_GEN_ROOT_FOLDER + File.separator
		 * + GlobalConstants.TEST_JSON_FILE;
		 * 
		 * String json = FileUtil.readFile(JSON_FILE_PATH,
		 * GlobalConstants.DEFAULT_ENCODING);
		 */

		/**************************************************************************/

		final String REST_GENERATOR_XML_PATH = GlobalConstants.WINDOWS_D_DRIVE
				+ File.separator + GlobalConstants.AND_GEN_ROOT_FOLDER
				+ File.separator + GlobalConstants.REST_GENERATOR_XML;

		CodeGenerator generator = CodeGeneratorFactory
				.buildCodeGenerator(REST_GENERATOR_XML_PATH);

		RESTWebServiceDescriptor descriptor = new RESTWebServiceDescriptor();

		descriptor.setJson(jsonReturn.getText());
		descriptor.setPackagePath(packagePath.getText());
		descriptor.setWebServiceName(webServiceName.getText());
		descriptor.setOperationName(operationName.getText());
		descriptor.setWebServiceURL(webServiceURL.getText());

		descriptor.setType(webServiceOperationType
				.getItem(webServiceOperationType.getSelectionIndex()));
		descriptor
				.setUrlFormat(urlFormat.getItem(urlFormat.getSelectionIndex()));

		descriptor.setParameters(parameterList);

		
		generator.generateIntegrationAndServiceCode(descriptor);
		
		GlobalConstants.globalCache.put(GlobalConstants.REST_GENERATOR,
				generator);
		

		generator.finish();

	}

	private void validateInputs() throws Exception {
		if (!StringUtil.matchPattern(StringUtil.PACKAGE_PATTERN,
				packagePath.getText())) {
			throw new Exception("Please enter a valid package name");
		}

		if (!StringUtil.matchPattern(StringUtil.JAVA_TYPES_PATTERN,
				webServiceName.getText())) {
			throw new Exception("Please enter a valid Webservice name");
		}

		if (!StringUtil.matchPattern(StringUtil.URL_PATTERN,
				webServiceURL.getText())) {
			throw new Exception("Please enter a valid Webservice URL");
		}

		if (!StringUtil.matchPattern(StringUtil.JAVA_METHOD_VARIABLES_NAMING_PATTERN,
				operationName.getText())) {
			throw new Exception("Please enter a valid Webservice Operation");
		}

		if (!StringUtil.isValidJson(jsonReturn.getText())) {
			throw new Exception("Please enter a valid JSON Return");
		}

		if (!StringUtil.isValidJson(jsonReturn.getText())) {
			throw new Exception("Please enter a valid JSON Return");
		}

		if (webServiceOperationType.getSelectionIndex() == -1) {
			throw new Exception("Please choose an Operation Type");
		}

		if (webServiceOperationType.getSelectionIndex() != 0) {
			throw new Exception(
					"Sorry only GET is supported currently. Other types will be supported in the stable version");
		}

		if (urlFormat.getSelectionIndex() == -1) {
			throw new Exception("Please choose a URL format");
		}

		validateParameters();

	}

	public void validateParameters() throws Exception {
		int parameterIndex = 1;
		parameterList.clear();

		for (ParameterUIComponent uiComponent : parameterUIComponentList) {

			if (uiComponent.getParameterType().getSelectionIndex() == -1) {
				throw new Exception("Error in Parameter " + parameterIndex
						+ ":Please choose a parameter type");
			}

			String parameterName = uiComponent.getParameterNameText().getText();
			String parameterValue = uiComponent.getParameterValueText()
					.getText();
			String parameterType = uiComponent.getParameterType().getItem(
					uiComponent.getParameterType().getSelectionIndex());

			if (!StringUtil.matchPattern(StringUtil.JAVA_METHOD_VARIABLES_NAMING_PATTERN,
					parameterName)) {
				throw new Exception("Error in Parameter " + parameterIndex
						+ ":Please enter a valid parameter name");
			}

			if (parameterType.equalsIgnoreCase("integer")) {
				if (!StringUtil.matchPattern(StringUtil.INTEGER_PATTERN,
						parameterValue)) {
					throw new Exception("Error in Parameter " + parameterIndex
							+ ":Please enter a valid integer default value");
				}
			} else if (parameterType.equalsIgnoreCase("float")) {
				if (!StringUtil.matchPattern(StringUtil.FLOAT_PATTERN,
						parameterValue)) {
					throw new Exception("Error in Parameter " + parameterIndex
							+ ":Please enter a valid float default value");
				}
			} else if (parameterType.equalsIgnoreCase("long")) {
				if (!StringUtil.matchPattern(StringUtil.LONG_PATTERN,
						parameterValue)) {
					throw new Exception("Error in Parameter " + parameterIndex
							+ ":Please enter a valid long default value");
				}
			} else if (parameterType.equalsIgnoreCase("double")) {
				if (!StringUtil.matchPattern(StringUtil.DOUBLE_PATTERN,
						parameterValue)) {
					throw new Exception("Error in Parameter " + parameterIndex
							+ ":Please enter a valid double default value");
				}
			} else if (parameterType.equalsIgnoreCase("boolean")) {
				if (!StringUtil.matchPattern(StringUtil.BOOLEAN_PATTERN,
						parameterValue)) {
					throw new Exception("Error in Parameter " + parameterIndex
							+ ":Please enter a valid boolean default value");
				}
			}

			Parameter parameter = new Parameter();
			parameter.setName(parameterName);
			parameter.setDefaultValue(parameterValue);
			parameter.setParameterType(parameterType);

			parameterList.add(parameter);

			parameterIndex++;

		}
	}

	private class ParameterUIComponent {
		private Text parameterNameText;
		private Text parameterValueText;
		private Combo parameterType;

		public Text getParameterNameText() {
			return parameterNameText;
		}

		public void setParameterNameText(Text parameterNameText) {
			this.parameterNameText = parameterNameText;
		}

		public Text getParameterValueText() {
			return parameterValueText;
		}

		public void setParameterValueText(Text parameterValueText) {
			this.parameterValueText = parameterValueText;
		}

		public Combo getParameterType() {
			return parameterType;
		}

		public void setParameterType(Combo parameterType) {
			this.parameterType = parameterType;
		}

	}

}
